﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TournamentOrganizerWPF
{
    [Serializable]
    public class Tournament
    {
        public ObservableCollection<Player> PlayerList { get; set; }
        public ObservableCollection<String> Locations { get; set; }
        public ObservableCollection<Match> PlayedMatches { get; set; }
        public ObservableCollection<Match> ActiveMatches { get; set; }
        public ObservableCollection<Scenario> ScenarioList { get; set; }
        public int RoundNo { get; set; }

        static Tournament instance = null;
        static readonly object padlock = new object();
        private bool scenariosShuffled = false;

        Tournament()
        {
            PlayerList = new ObservableCollection<Player>();
            Locations = new ObservableCollection<string>();
            PlayedMatches = new ObservableCollection<Match>();
            ScenarioList = new ObservableCollection<Scenario>();
         

            Locations.Add("Default location");
        }

        public static Tournament Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new Tournament();
                    }
                    return instance; 
                }
            }
        }

        public void AddPlayer(Player player)
        {
            PlayerList.Add(player);
        }

        public void MatchNextRound()
        {
            
            var matchListWindow = new MatchListWindow(this);
          

            if (PlayerList.Count % 2 == 1)
            {
                PlayerList.Add(new Player(PlayerList.Count+1, "Stand-in", "None"));
            }

            if (RoundNo == 0)
            {
                ActiveMatches = MatchMaking.MatchPlayersFirstRound(PlayerList, Locations, PlayedMatches.Count);
                RoundNo++;
                matchListWindow.Show();
            }
            else
            {
                if (RoundComplete())
                {
                    if (ActiveMatches != null)
                    {
                        foreach (var match in ActiveMatches)
                        {
                            PlayedMatches.Add(match);
                        }

                        ActiveMatches.Clear();
                    }

                    ActiveMatches = MatchMaking.MatchPlayersNextRound(PlayerList, PlayedMatches.Count);
                    RoundNo++;
                    matchListWindow.Show();

                }
                else
                {
                    matchListWindow.Show();
                }

            }            
        }

        public bool RoundComplete()
        {
            const bool isComplete = true;

            if (ActiveMatches != null)
            {
                foreach (var match in ActiveMatches)
                {
                    if (match.WinningPlayer == null)
                    {
                        return false;
                    }
                }
            }
            
            return isComplete;
        }

        public void ReportResult(Match match)
        {
            Player player1 = PlayerList.Single(player => player.Id == match.Player1.Id);
            Player player2 = PlayerList.Single(player => player.Id == match.Player2.Id);
            player1.ControlPoints = player1.ControlPoints + match.ControlPointsPlayer1;
            player2.ControlPoints = player2.ControlPoints + match.ControlPointsPlayer2;

            if (match.WinningPlayer.Equals(player1))
            {
                player1.Wins++;
            }
            else
            {
                player2.Wins++;
            }

            player1.AddMatch(match);
            player2.AddMatch(match);

            player1.SetOpponent(player2);
            player2.SetOpponent(player1);

            player1.CalculatePoints();
            player2.CalculatePoints();
            
            PlayerList.Remove(player1);
            PlayerList.Add(player1);

            PlayerList.Remove(player2);
            PlayerList.Add(player2);

            var newList = (from players in PlayerList
                          orderby players.ControlPoints descending
                          orderby players.Wins descending
                          select players).ToList();

            PlayerList.Clear();

            foreach (var item in newList)
            {
                PlayerList.Add(item);
            }
        }

        public void PrintMatches()
        {
            var sb = new StringBuilder();
            var file = new StreamWriter("Matches.txt");

            if (ActiveMatches != null)
                foreach (var match in ActiveMatches)
                {
                    sb.Append(match.ToString()).Append("\r\n\r\n");
                }

            file.WriteLine(sb.ToString());
            file.Close();
        }

        public void PrintStandings()
        {
            var sb = new StringBuilder();
            var file = new StreamWriter("Standings.txt");
            var placement = 1;

            if (PlayerList != null)
                foreach (var player in PlayerList)
                {
                    sb.Append(placement + ": " + player.StringToPrint()).Append("\r\n");
                    placement++;
                }   

            file.WriteLine(sb.ToString());
            file.Close();
        }

        public void AddScenario(string scenarioName)
        {
            if (!scenariosShuffled)
            {
                ScenarioList.Add(new Scenario(scenarioName));
            }
            
        }

        public void ShuffleAndPick()
        {
            if (!scenariosShuffled && ScenarioList.Count >= 5)
            {
                var tempList = new List<Scenario>();
                var roundNo = 1;
                var random = new Random();

                for (int i = 0; i < 5; i++)
                {
                    int number = random.Next(ScenarioList.Count);
                    ScenarioList.ElementAt(number).Round = roundNo;
                    tempList.Add(ScenarioList.ElementAt(number));
                    ScenarioList.RemoveAt(number);
                    roundNo++;
                }

                tempList = (from scenarios in tempList
                               orderby scenarios.Round ascending
                               select scenarios).ToList();
                ScenarioList.Clear();

                foreach (var scenario in tempList)
                {
                    ScenarioList.Add(scenario);
                }
                scenariosShuffled = true;
            }
        }
    }
}
